<template>
  <div class="grid" style="gap: 12px">
    <GlassCard>
      <el-form
        label-position="left"
        label-width="40px"
        size="small"
        class="color-compact">
        <!-- Hex -->
        <el-form-item label="Hex">
          <div class="row-input">
            <el-input
              size="small"
              v-model="state.hex"
              style="width: 140px"
              @input="onHexChange" />
            <el-button circle text size="small" @click="copy(state.hex)">
              <el-icon><DocumentCopy /></el-icon>
            </el-button>
          </div>
        </el-form-item>

        <!-- RGB -->
        <div
          style="
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
          ">
          <el-form-item label="R">
            <el-input
              size="small"
              type="number"
              v-model.number="state.r"
              min="0"
              max="255"
              style="width: 100%"
              @input="onRgbChange" />
          </el-form-item>
          <el-form-item label="G">
            <el-input
              size="small"
              type="number"
              v-model.number="state.g"
              min="0"
              max="255"
              style="width: 100%"
              @input="onRgbChange" />
          </el-form-item>
          <el-form-item label="B">
            <el-input
              size="small"
              type="number"
              v-model.number="state.b"
              min="0"
              max="255"
              style="width: 100%"
              @input="onRgbChange" />
          </el-form-item>
        </div>

        <!-- HSL -->
        <div
          style="
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
          ">
          <el-form-item label="H(°)">
            <el-input
              size="small"
              type="number"
              v-model.number="state.h"
              min="0"
              max="360"
              style="width: 100%"
              @input="onHslChange" />
          </el-form-item>
          <el-form-item label="S(%)">
            <el-input
              size="small"
              type="number"
              v-model.number="state.s"
              min="0"
              max="100"
              style="width: 100%"
              @input="onHslChange" />
          </el-form-item>
          <el-form-item label="L(%)">
            <el-input
              size="small"
              type="number"
              v-model.number="state.l"
              min="0"
              max="100"
              style="width: 100%"
              @input="onHslChange" />
          </el-form-item>
        </div>

        <!-- Preview & CSS variables -->
        <div class="preview">
          <div class="swatch" :style="{ background: state.hex }"></div>
          <div class="codes">
            <div class="code-line">
              <span class="label">hex</span>
              <span class="code">{{ state.hex }}</span>
              <el-button circle text size="small" @click="copy(state.hex)">
                <el-icon><DocumentCopy /></el-icon>
              </el-button>
            </div>
            <div class="code-line">
              <span class="label">rgb</span>
              <span class="code"
                >rgb({{ state.r }}, {{ state.g }}, {{ state.b }})</span
              >
              <el-button
                circle
                text
                size="small"
                @click="copy(`rgb(${state.r}, ${state.g}, ${state.b})`)">
                <el-icon><DocumentCopy /></el-icon>
              </el-button>
            </div>
            <div class="code-line">
              <span class="label">hsl</span>
              <span class="code"
                >hsl({{ state.h }}, {{ state.s }}%, {{ state.l }}%)</span
              >
              <el-button
                circle
                text
                size="small"
                @click="copy(`hsl(${state.h}, ${state.s}%, ${state.l}%)`)">
                <el-icon><DocumentCopy /></el-icon>
              </el-button>
            </div>
          </div>
        </div>
      </el-form>
    </GlassCard>
  </div>
</template>

<script setup lang="ts">
import { DocumentCopy } from "@element-plus/icons-vue"
import {
  ElButton,
  ElForm,
  ElFormItem,
  ElIcon,
  ElInput,
  ElInputNumber,
  ElMessage
} from "element-plus"
import { reactive, watch } from "vue"

// @ts-ignore - SFC default export by Vue plugin
import GlassCard from "./ui/GlassCard.vue"

type LastEdited = "hex" | "rgb" | "hsl" | null

const state = reactive({
  hex: "#1489fe",
  r: 20,
  g: 137,
  b: 254,
  h: 213,
  s: 99,
  l: 54,
  last: null as LastEdited
})

function clamp(n: number, min: number, max: number) {
  return Math.min(max, Math.max(min, n))
}

// Utils: conversions
function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
  const h = hex.trim().replace(/^#/, "")
  if (!/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(h)) return null
  const full =
    h.length === 3
      ? h
          .split("")
          .map((c) => c + c)
          .join("")
      : h
  const num = parseInt(full, 16)
  return { r: (num >> 16) & 255, g: (num >> 8) & 255, b: num & 255 }
}
function rgbToHex(r: number, g: number, b: number): string {
  const to2 = (n: number) => clamp(n, 0, 255).toString(16).padStart(2, "0")
  return `#${to2(r)}${to2(g)}${to2(b)}`.toLowerCase()
}
function rgbToHsl(
  r: number,
  g: number,
  b: number
): { h: number; s: number; l: number } {
  r /= 255
  g /= 255
  b /= 255
  const max = Math.max(r, g, b),
    min = Math.min(r, g, b)
  let h = 0,
    s = 0,
    l = (max + min) / 2
  if (max !== min) {
    const d = max - min
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
    switch (max) {
      case r:
        h = (g - b) / d + (g < b ? 6 : 0)
        break
      case g:
        h = (b - r) / d + 2
        break
      case b:
        h = (r - g) / d + 4
        break
    }
    h /= 6
  }
  return {
    h: Math.round(h * 360),
    s: Math.round(s * 100),
    l: Math.round(l * 100)
  }
}
function hslToRgb(
  h: number,
  s: number,
  l: number
): { r: number; g: number; b: number } {
  h = ((h % 360) + 360) % 360
  s = clamp(s, 0, 100) / 100
  l = clamp(l, 0, 100) / 100
  const c = (1 - Math.abs(2 * l - 1)) * s
  const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
  const m = l - c / 2
  let r1 = 0,
    g1 = 0,
    b1 = 0
  if (h < 60) {
    r1 = c
    g1 = x
    b1 = 0
  } else if (h < 120) {
    r1 = x
    g1 = c
    b1 = 0
  } else if (h < 180) {
    r1 = 0
    g1 = c
    b1 = x
  } else if (h < 240) {
    r1 = 0
    g1 = x
    b1 = c
  } else if (h < 300) {
    r1 = x
    g1 = 0
    b1 = c
  } else {
    r1 = c
    g1 = 0
    b1 = x
  }
  return {
    r: Math.round((r1 + m) * 255),
    g: Math.round((g1 + m) * 255),
    b: Math.round((b1 + m) * 255)
  }
}

// Handlers
function onHexChange() {
  const rgb = hexToRgb(state.hex)
  if (!rgb) return
  state.last = "hex"
  state.r = rgb.r
  state.g = rgb.g
  state.b = rgb.b
  const hsl = rgbToHsl(state.r, state.g, state.b)
  state.h = hsl.h
  state.s = hsl.s
  state.l = hsl.l
}
function onRgbChange() {
  state.last = "rgb"
  state.hex = rgbToHex(state.r, state.g, state.b)
  const hsl = rgbToHsl(state.r, state.g, state.b)
  state.h = hsl.h
  state.s = hsl.s
  state.l = hsl.l
}
function onHslChange() {
  state.last = "hsl"
  const rgb = hslToRgb(state.h, state.s, state.l)
  state.r = rgb.r
  state.g = rgb.g
  state.b = rgb.b
  state.hex = rgbToHex(state.r, state.g, state.b)
}

watch(
  () => [state.r, state.g, state.b],
  (nv, ov) => {
    if (state.last !== "rgb") onRgbChange()
  }
)
watch(
  () => [state.h, state.s, state.l],
  (nv, ov) => {
    if (state.last !== "hsl") onHslChange()
  }
)
watch(
  () => state.hex,
  () => {
    if (state.last !== "hex") onHexChange()
  }
)

async function copy(text: string) {
  try {
    await navigator.clipboard.writeText(text)
    ElMessage.success("已复制")
  } catch {
    ElMessage.error("复制失败")
  }
}
</script>

<style scoped>
.color-compact :deep(.el-form-item) {
  margin-bottom: 10px;
}
.row-input {
  display: flex;
  align-items: center;
  gap: 8px;
}
.preview {
  display: grid;
  grid-template-columns: 72px 1fr;
  gap: 12px;
  align-items: center;
}
.swatch {
  width: 72px;
  height: 72px;
  border-radius: 10px;
  border: 1px solid #e3edf5;
}
.codes {
  display: grid;
  gap: 4px;
}
.code-line {
  display: grid;
  grid-template-columns: 40px 1fr 28px;
  align-items: center;
  gap: 6px;
}
.code-line .label {
  color: #4b5b76;
  font-weight: 600;
  text-transform: lowercase;
}
.code-line .code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
</style>
